home *** CD-ROM | disk | FTP | other *** search
- General Routines
- ----------------
- With the release of 4.0 we have made changes to help support those people
- who want to program in other languages like C. This means that when you
- create keys for the Wildcat! 4 databases you must first pack them using the
- standard WordToKey routine (or LongToKey) and then call the Filer routine
- CStyleNumKey. This strips all the nulls from the key and makes it ascii
- compliant. Here are the two routines used in the database modules:
-
-
- function Word2Key(Num : Word) : String;
- begin
- Word2Key := CStyleNumKey(WordToKey(Num));
- end;
-
- function Long2Key(Num : LongInt) : String;
- begin
- Long2Key := CStyleNumKey(LongToKey(Num));
- end;
-
-
- If you need to do a KeyToWord (or KeyToLong) first call the PascalStyleNumKey
- routine and then call KeyToWord.
-
- *** READ THE FOLLOWING ***
-
- You will want to add a two lines of code to the CStyleNumKey and the
- PascalStyleNumKey to fix a problem with the Btree Filer 5.41 routines,
- In the CStyleNumKeys add this line:
-
-
- OrigLen := Length(S);
- if (OrigLen = 0) or (OrigLen > MaxInpStrLen) then begin
- CStyleNumKey := '';
- Exit;
- end;
- S[OrigLen+1] := #0; <---- Add This Line
-
-
- And in the PascalStyleNumKeys add the same line:
-
-
- OrigLen := Length(S);
- if OrigLen = 0 then begin
- PascalStyleNumKey := '';
- Exit;
- end;
- S[OrigLen+1] := #0; <---- Add This Line
-
-
-
- File Database
- -------------
-
- The main file database is a Btree Filer database with four keys. There
- is also a secondary index file that is not generated with Filer to
- support fast searching of the file database. This secondary index will
- be documented in later versions of this file. This Filer database is a
- variable record sized Filer database. The section size of this
- database is 291 bytes, this is the number that must be passed to
- BtCreateFileBlock when creating a file database. The extended
- description of a file is an array of characters layed out in the
- following format: 1) There is a line length limit of 79 characters,
- each line is ended with a CR character making the length of a full line
- 80 bytes. 2) There may be up to 15 lines in the extended description,
- adding more lines will corrupt the database and possibly corrupt memory
- inside of Wildcat causing a crash. There is no ^Z terminator at the
- end of the description as there was in previous versions of Wildcat.
- The MsgBytes field in the TFileRec should be set to the total number of
- bytes in the array including the end of line characters. Here is a
- list of the keys and the IsamIndDescr structure you pass to
- BtCreateFileBlock when creating the database:
-
- const
- FileAreaKey = 1;
- FileNameKey = 2;
- FileDateKey = 3;
- FileUpKey = 4;
-
- IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
-
- IID[FileAreaKey].KeyL := 15;
- IID[FileAreaKey].AllowDupK := False;
- IID[FileNameKey].KeyL := 15;
- IID[FileNameKey].AllowDupK := False;
- IID[FileDateKey].KeyL := 12;
- IID[FileDateKey].AllowDupK := True;
- IID[FileUpKey].KeyL := 30;
- IID[FileUpKey].AllowDupK := True;
-
- Here is a sample routine to create the keys for a file record in the
- file database:
-
- function BuildKey(const FileRec : TFileRec; Key : Integer) : IsamKeyStr;
- begin
- with FileRec do
- case Key of
- FileAreaKey : BuildKey := Word2Key(Area)+StUpcase(Pad(FileName, 12));
- FileNameKey : BuildKey := StUpcase(Pad(FileName, 12))+Word2Key(Area);
- FileDateKey : BuildKey := Word2Key(Area)+Word2Key(FileTime.D)+Long2Key(FileTime.T);
- FileUpKey : BuildKey := Pad(StUpCase(Uploader), 25)+Long2Key(UploaderId);
- end;
- end;
-
-
- User Database
- -------------
-
- The main user database is a Btree Filer database with six keys. The username
- key is no longer unique as we are now allowing users with duplicate names
- to be in the database, there are now two unique keys, the users alias and the
- users ID. The user database stores the highest user number in the MasterInfo
- record of NODEINFO.DAT (record 0), the database also verifies the number by
- comparing the highest user ID key with the number in MasterInfo. Here is the
- layout for the new user database:
-
- UserNameKey = 1;
- UserSecKey = 2;
- UserExpDateKey = 3;
- UserAliasKey = 4;
- UserIdKey = 5;
- UserRealKey = 6;
-
- IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
-
- DataLen := SizeOf(TUserRec);
- Keys := 6;
- IID[1].KeyL := 30; {UserName + UserID Key}
- IID[1].AllowDupK := False;
- IID[2].KeyL := 35; {SecLevel + UserName Key}
- IID[2].AllowDupK := True;
- IID[3].KeyL := 3; {Expired Date Key}
- IID[3].AllowDupK := True;
- IID[4].KeyL := 25; {User Alias Key}
- IID[4].AllowDupK := False;
- IID[5].KeyL := 5; {User ID Key}
- IID[5].AllowDupK := False;
- IID[6].KeyL := 25; {User Real Name}
- IID[6].AllowDupK := True;
-
-
- Here is a sample routine to create the keys for a user record in the
- user database:
-
- function SwitchLast(const Name : Str25) : Str25;
- var
- X, Y : Byte;
-
- begin
- Y := Length(Name);
- X := Y;
- while (Y > 0) and (Name[Y] <> ' ') do
- Dec(Y);
- if Y = 0 then
- SwitchLast := Name
- else
- SwitchLast := Copy(Name, Succ(Y), X - Y) + ' ' + Copy(Name, 1, Pred(Y));
- end;
-
- function BuildUserNameKey(const Name : String; UserID : LongInt) : IsamKeyStr;
- begin
- BuildUserNameKey := Pad(StUpCase(SwitchLast(Name)), 25)+Long2Key(UserID);
- end;
-
-
- function BuildUserIDKey(IDName : LongInt) : IsamKeyStr;
- begin
- BuildUserIDKey := Long2Key(IDName);
- end;
-
-
- function TUserDatabase.BuildKey(const Data; Key : Integer) : IsamKeyStr;
- var
- UserRec : TUserRec absolute Data;
-
- begin
- with UserRec do
- case Key of
- 1 : BuildKey := BuildUserNameKey(UserName, UserID);
- 2 : BuildKey := Pad(SecLevel, 10)+StUpCase(SwitchLast(UserName));
- 3 : BuildKey := Word2Key(ExpireDate);
- 4 : if UserRec.Alias = '' then
- BuildKey := ''
- else
- BuildKey := StUpCase(Alias);
- 5 : BuildKey := BuildUserIDKey(UserId);
- 6 : BuildKey := StUpCase(UserName);
- end;
- end;
-
-
- function TUserDatabase.AddRecord(var RefNr : LongInt; var Data) : Boolean;
- var
- UserRec : TUserRec absolute Data;
- ConfPage : TUserConfPage;
- RefKey : IsamKeyStr;
- UserRef : LongInt;
-
- begin
- AddRecord := False;
- Lock;
- if MwConfig.DupUserLevel <> duAllow then
- if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
- begin
- Unlock;
- Exit;
- end;
- Unlock;
- ReadMInfo(True);
- ClearKey(UserIDKey);
- PrevKey(UserIDKey, UserRef, RefKey);
- if IsamOk then
- UserRef := Key2Long(RefKey)
- else
- UserRef := 0;
- if UserRef > MInfo.HighestUserId then
- MInfo.HighestUserId := UserRef + 1
- else
- Inc(MInfo.HighestUserId);
- WriteMInfo;
- Lock;
- (*
- we now have to recheck the duplicate situation, in weird cases we make
- increment the highest user id without adding a new user but this is
- required to prevent deadlock situations
- *)
- if MwConfig.DupUserLevel <> duAllow then
- if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
- begin
- Unlock;
- Exit;
- end;
- UserRec.UserId := MInfo.HighestUserId;
- UserRec.UserConfData := 0;
- if inherited AddRecord(RefNr, Data) then
- begin
- AddRecord := True;
- UserConfDb.GetPage(UserRec, 0, ConfPage);
- end;
- Unlock;
- end;
-
-
- Security Profiles
- -----------------
-
- Wildcat 4.0 adds support for up to 32,760 conferences and 32,760 file
- areas, as a result of this certain fields in the security profiles are
- now variable sized. Also when a Wildcat is configured for a large
- number of conferences or file areas the data structures for these
- variable sized pieces of the security profile can get so large that it
- is not possible to keep them in memory all at once. If your program
- must conserve memory we recommend using a paging scheme to only keep
- part of the variable sized data in memory at once. Wildcat uses a
- scheme like this in which Wildcat only uses 2K to access 24K of data
- that will exist in the worst case system. There are also two types of
- security profiles, Primary and Secondary. Primary profiles are the
- ones you edit and use to set a users options, the secondary is used for
- setting a users access to certain areas, specifically those with bit
- access. What Wildcat does is load the users primary profile and then
- load each secondary and logically OR the bits for doors, nodes,
- protocols and menu items, then it pages the conf/file bits and OR's
- those with the primary file and when it is finished it writes the new
- profile to the users wcwork/node directory where Wildcat uses it to
- determine file and conference access. Use the TSec header to determine
- what type of profile you are looking at.
-
- Here is the layout of the security records in the SECLEVEL.DAT:
-
- /* First record */
- TSecRec record from WCTYPE.PAS
- ((Number of conferences * 3) - 1) div 8 + 1 of bytes of conference security info
- ((Number of file areas * 3) - 1) div 8 + 1 of bytes of conference security info
-
- /* Second record */
- TSecRec record from WCTYPE.PAS
- ((Number of conferences * 3) - 1) div 8 + 1 of bytes of file area security info
- ((Number of file areas * 3) - 1) div 8 + 1 of bytes of file area security info
-
- And so on....
-
- To compute the exact size of a record in the system you would do something
- like this:
-
- function SecRecSize : LongInt;
- var
- FileBitSize,
- ConfBitSize : LongInt;
-
- begin
- ConfBitSize := ((LongInt(Number of conferences) * 3) - 1) div 8 + 1;
- FileBitSize := ((LongInt(Number of file areas) * 3) - 1) div 8 + 1;
- SecRecSize := LongInt(SizeOf(TSecRec)) + ConfBitSize + FileBitSize;
- end;
-
- What do the security bits mean?
- -------------------------------
-
- sConfRead = $01; {The first bit gives the user access to read messages in the conference}
- sConfWrite = $02; {The second bit gives the user access to write messages in the conference}
- sConfJoin = $04; {The third bit gives the user access to join the conference}
-
- function GetConfAccess(Conf : Word) : Byte;
- begin
- I := Conf * 3;
- GetConfAccess := (Word((address of conf data[I div 8])^) shr (I mod 8)) and $07;
- end;
-
- The above function will return the bits for the specified conference if you
- point the function at where you load the conference data into memory. You
- can then test for various options using the and operator like this:
-
- if (GetConfAccess(9) and sConfRead = sConfRead) then begin
- {user has conference read access in conference 9}
- end;
-
- sFileList = $01; {The first bit gives the user access list files in the area}
- sFileDown = $02; {The second bit gives the user access to download files in the area}
- sFileUp = $04; {The third bit gives the user access to upload files in the area}
-
- function GetFileAccess(Area : Word) : Byte;
- begin
- I := (Area - 1) * 3;
- {!! It is important to notice that we decrement the file area, this !!}
- {!! is because file areas are numbered starting at 1, we decrement !!}
- {!! the area so we don't skip the first three bits in the data !!}
- {!! structure. !!}
- GetAreaAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $07;
- end;
-
- The above function will return the bits for the specified file area if you
- point the function at where you load the file data into memory. You
- can then test for various options using the and operator like this:
-
- if (GetFileAccess(7) and sFileList = sFileList) then begin
- {user has file list access in file area 7}
- end;
-
- Conference Definition Records
- -----------------------------
-
- The conference records in Wildcat 4.0 are also variable sized for the same
- reasons metioned in the section on Security Profiles. The layout of the
- conference records is as follows:
-
- {first record}
- TConfDesc record from WCTYPE.PAS
- (Number of file areas - 1) div 8 + 1 of bytes of file area info
-
- {second record}
- TConfDesc record from WCTYPE.PAS
- (Number of file areas - 1) div 8 + 1 of bytes of file area info
-
- {... and so on}
-
- To compute the actual size of each Conference record in the CONFDESC.DAT file
- you can use the following function:
-
- function ConfRecSize : Word;
- var
- FileRecSize : Word;
-
- begin
- FileRecSize := (Number of file areas - 1) div 8 + 1;
- ConfRecSize := SizeOf(TConfDesc) + FileRecSize;
- end;
-
-
- What do the file area bits mean?
- --------------------------------
-
- Each bit in the file area data at the end of each TConfDesc is used to
- determine whether that conference will allow the user to access the
- particular file area. For example if the 10th bit is set the the conference
- makes file area 10 available to the caller if their security access
- permits it.
-
- function GetConfFileAccess(Area : Word) : Boolean;
- begin
- I := Conf * 3;
- GetConfFileAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $01 = $01;
- end;
-
-